package org.wutopia.labcloud.domain.order.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.seata.rm.tcc.api.BusinessActionContext;
import org.apache.seata.spring.annotation.GlobalTransactional;

import org.springframework.stereotype.Service;
import org.wutopia.labcloud.domain.order.constant.OrderStatusType;
import org.wutopia.labcloud.domain.order.controller.vo.input.OrderCreateOrderInputVO;
import org.wutopia.labcloud.domain.order.controller.vo.input.OrderPayInputVO;
import org.wutopia.labcloud.domain.order.controller.vo.input.OrderProductList;
import org.wutopia.labcloud.domain.order.dao.OrderMainDao;
import org.wutopia.labcloud.domain.order.dao.OrderProductRDao;
import org.wutopia.labcloud.domain.order.dao.entity.OrderMain;
import org.wutopia.labcloud.domain.order.dao.entity.OrderProductR;
import org.wutopia.labcloud.domain.order.mq.producer.OrderProducer;
import org.wutopia.labcloud.domain.order.service.OrderService;
import org.wutopia.labcloud.service.api.service.dubbo.DubboProductService;
import org.wutopia.labcloud.service.api.service.dubbo.dto.output.DubboGetProductOutputDTO;
import org.wutopia.labcloud.service.api.service.seata.TccPaymentService;
import org.wutopia.labcloud.service.api.service.seata.TccProductService;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@AllArgsConstructor
@Slf4j
public class OrderServiceImpl implements OrderService {

    private OrderMainDao orderMainDao;

    private OrderProductRDao orderProductRDao;

    @DubboReference
    private DubboProductService dubboProductService;

    @DubboReference
    private TccProductService tccProductService;

    @DubboReference
    private TccPaymentService tccPaymentService;

    private OrderProducer orderProducer;

    @Override
    @GlobalTransactional
    public void createOrder(OrderCreateOrderInputVO vo) throws Exception {

        List<OrderProductList> productList = vo.getProductList();

        BigDecimal realPrice = BigDecimal.ZERO;
        for (OrderProductList orderProductList : productList) {

            DubboGetProductOutputDTO productById = dubboProductService.getProductById(orderProductList.getProductId());

            BigDecimal apply = productById.getPrice();
            realPrice = realPrice.add(apply);
        }

        log.info("订单总价：{}", realPrice);

        OrderMain orderMain = new OrderMain();

        orderMain.setUserId(vo.getUserId());
        orderMain.setUserDeliveryAddrId(vo.getUserDeliveryAddrId());
        orderMain.setTotalPrice(realPrice);
        orderMain.setRealPrice(realPrice);
        orderMain.setStatus(OrderStatusType.NON_PAID);
        orderMainDao.insert(orderMain);

        BusinessActionContext actionContext = new BusinessActionContext();



        for (OrderProductList item : productList) {


            tccProductService.productStockpileFrozen(actionContext, item.getProductId(), item.getProductAmount());


            OrderProductR orderProductR = new OrderProductR();
            orderProductR.setProductAmount(item.getProductAmount());
            orderProductR.setProductId(item.getProductId());
            orderProductR.setOrderId(orderMain.getId());
            orderProductRDao.insert(orderProductR);
        }

        orderProducer.sendDelayedOrder(orderMain.getId(), 16, "timeout");
    }

    @Override
    @GlobalTransactional
    public void pay(OrderPayInputVO vo) throws Exception {

        // 1. 支付订单
        OrderMain orderMain = orderMainDao.selectById(vo.getOrderId());

        BusinessActionContext actionContext = new BusinessActionContext();

        Map<String, Object> map = new HashMap<>();
        map.put("userId", orderMain.getUserId());
        map.put("orderId", orderMain.getId());
        map.put("frozen", orderMain.getRealPrice());
        actionContext.setActionContext(map);
        Long payId = tccPaymentService.frozenMoney(actionContext, vo.getPassword(), vo.getUserId(), vo.getOrderId(), orderMain.getRealPrice());

        // 3. 更新订单支付id和支付type

        orderMain.setPayId(payId);
        orderMain.setPayType("wallet");
        orderMainDao.updateById(orderMain);

        // 4. 模拟配送到达，延迟一天发送货物到达信息
        orderProducer.sendDelayedOrder(orderMain.getId(), 18, "delivered");
    }

    @Override
    @GlobalTransactional
    public void cancel(Long orderId) throws Exception {
        OrderMain orderMain = orderMainDao.selectById(orderId);

        // 2. 产品冻结库存还原
        QueryWrapper<OrderProductR> q = new QueryWrapper<>();
        q.eq("order_id", orderId);
        List<OrderProductR> orderProductRS = orderProductRDao.selectList(q);

        BusinessActionContext actionContext = new BusinessActionContext();

        for (OrderProductR r : orderProductRS) {
            Map<String, Object> map = new HashMap<>();
            map.put("productId", r.getProductId());
            map.put("frozen", r.getProductAmount());
            actionContext.setActionContext(map);
            tccProductService.stockpileFrozenReturn(actionContext, r.getProductId(), r.getProductAmount());
        }

        // 3. 如果订单状态为 未送达，未确认表示已支付订单，所以要，钱包冻结金额还原
        if(orderMain.getStatus().equals(OrderStatusType.UNDELIVERED) || orderMain.getStatus().equals(OrderStatusType.UNCONFIRMED)) {
            Map<String, Object> map = new HashMap<>();
            map.put("userId", orderMain.getUserId());
            map.put("orderId", orderMain.getId());
            map.put("frozen", orderMain.getRealPrice());
            actionContext.setActionContext(map);

            tccPaymentService.moneyReturn(actionContext, orderMain.getUserId(), orderMain.getId(), orderMain.getRealPrice());
        }

        // 1. 设置订单为取消状态
        orderMain.setStatus(OrderStatusType.CANCELED);
        orderMainDao.updateById(orderMain);
    }

    @Override
    public void confirmed(Long orderId) throws Exception {
        OrderMain orderMain = orderMainDao.selectById(orderId);

        QueryWrapper<OrderProductR> q = new QueryWrapper<>();
        q.eq("order_id", orderId);
        List<OrderProductR> orderProductRS = orderProductRDao.selectList(q);

        BusinessActionContext actionContext = new BusinessActionContext();

        // 1. 释放库存
        for (OrderProductR r : orderProductRS) {
            Map<String, Object> map = new HashMap<>();
            map.put("productId", r.getProductId());
            map.put("frozen", r.getProductAmount());
            actionContext.setActionContext(map);
            tccProductService.stockpileFrozenRelease(actionContext, r.getProductId(), r.getProductAmount());
        }

        // 2. 释放账户金额

        Map<String, Object> map = new HashMap<>();
        map.put("userId", orderMain.getUserId());
        map.put("orderId", orderMain.getId());
        map.put("frozen", orderMain.getRealPrice());
        actionContext.setActionContext(map);

        tccPaymentService.frozenRelease(actionContext, orderMain.getUserId(), orderMain.getId(), orderMain.getRealPrice());


        // 3. 修改订单状态
        orderMain.setStatus(OrderStatusType.COMPLETED);
        orderMainDao.updateById(orderMain);
    }


}
